package com.example.shop.common.configs;

import com.alibaba.fastjson.JSONObject;
import com.example.shop.base.Result;
import com.example.shop.common.annotation.LoginIgnore;
import com.example.shop.common.exception.ApiLoginException;
import com.example.shop.common.utils.Constants;
import com.example.shop.common.utils.RedisService;
import com.example.shop.common.utils.SHA256;
import com.example.shop.common.utils.SpringUtils;
import com.example.shop.domain.wx.UserInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

/**
 * api接口拦截器
 * 参数封装加密校验
 * @author haocjia
 */
public class ApisInterceptor implements HandlerInterceptor {

    @Value("${system.secretKey}")
    private String secretKey;

    private RedisService redisService = SpringUtils.getBean("redisService");

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception {

        Map<String, String[]> params = request.getParameterMap();
        // 处理参数
        Map<String, Object> map = handlerParam(params);

        String signature = map.get(Constants.SIGNATURE).toString();

        if (StringUtils.isBlank(signature)) {
            errorResponse(response, "参数异常");
            return false;
        }

        Long timestamp = Long.valueOf(map.get(Constants.TIME_STAMP).toString());

        if (timestamp == null) {
            errorResponse(response, "参数异常");
            return false;
        }

        // 获取请求时间差 秒数
        Long s = ((System.currentTimeMillis() - timestamp) / 1000);
        // 同一个完整的请求url 在十五秒内可重复执行
        if (s > 6) {
            errorResponse(response, "参数异常");
            return false;
        }

        /**
         * 检验参数加密 是否相等
         */
        String key = SHA256.getSHA256Str(map.get("signStr").toString() + secretKey);
        if (!signature.equals(key)) {
            errorResponse(response, "参数异常");
            return false;
        }

        // 忽略需要登录的接口
        LoginIgnore ignore = ((HandlerMethod) handler).getMethodAnnotation(LoginIgnore.class);
        if (ignore != null) {
            return true;
        }

        String token = request.getHeader("token");
        if (StringUtils.isBlank(token)) {
            UserInfo userInfo = (UserInfo) redisService.get(Constants.WX_API_TOKEN + token);
            if (userInfo == null) {
                errorResponse(response, "请先登录");
                return false;
            }
        }
        return true;
    }

    private void errorResponse(HttpServletResponse response, String msg) throws IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println(JSONObject.toJSON(Result.error(msg)));
        writer.close();
    }

    private Map<String, Object> handlerParam(Map<String, String[]> params) throws UnsupportedEncodingException {
        Map<String, Object> objectMap = new HashMap<>();

        Map<String, Object> map = new HashMap<>();
        ;
        for (Map.Entry<String, String[]> vo : params.entrySet()) {
            if (vo.getKey().equals(Constants.SIGNATURE)) {
                String[] value = vo.getValue();
                // 取出加密字符参数
                objectMap.put(Constants.SIGNATURE, value[0]);
            } else {
                String[] value = vo.getValue();
                if (vo.getKey().equals(Constants.TIME_STAMP)) {
                    objectMap.put(Constants.TIME_STAMP, value[0]);
                }
                map.put(vo.getKey(), value[0]);
            }
        }
        // 字典排序
        List<Map.Entry<String, Object>> entryList = new ArrayList<>(map.entrySet());
        // 对所有传入参数按照字段名的 ASCII 码从小到大排序（字典序）
        Collections.sort(entryList, Comparator.comparing(Map.Entry::getKey));
        // 参数集合
        objectMap.put("params", entryList);

        // 构造加密字符串
        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, Object> entry : entryList) {
            sb.append(entry.getKey() + "=" + entry.getValue().toString());
            sb.append("&");
        }
        objectMap.put("signStr", sb.toString());

        return objectMap;
    }

    public static void main(String[] args) {
        String a = "{\"randomStr\":\"74273bfa-2655-483c-824a-d321b9437a7f\",\"bookInfoId\":\"c4fdb7b9150511ea9d1af48e38bb6989\",\"timestamp\":\"1576200412844\"}";
    }
}
